﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Windows.Forms;

namespace EyeTracker_IA_Project
{
    /// <summary>
    /// Un generico punto 
    /// </summary>
    public class GazePoint
    {
        public int x;
        public int y;
        public int timeFix;
        public int numFix;
        public GazePoint(int x, int y) 
        {
            this.x = x; this.y = y; timeFix = 0; this.numFix = 1;
        }
        public void addTime() { this.timeFix+=1; }
        public void addTimeValue(int add) { this.timeFix +=add; }
        public void zero() { this.x = 0; this.y = 0; this.timeFix = 0; this.numFix = 0; }
        /// <summary>
        /// vede se il punto e' in un intorno del gazepoint
        /// </summary>
        /// <param name="p">Point : il punto da confrontare</param>
        /// <returns></returns>
        public bool equalsPoint(System.Drawing.Point p)
        {
            if ( Math.Abs(this.x - p.X)<8 && Math.Abs(this.y - p.Y)<5 )
                return true;
            return false;
        }
        public bool equalsGazePoint(GazePoint g)
        {
            if (Math.Abs(this.x - g.x) < 8 && Math.Abs(this.y - g.y) < 5)
                return true;
            return false;
        }
    }
    
    /// <summary>
    /// Le word formattate per essere scritte dal parser su xml
    /// </summary>
    public struct WordFixXML
    {
        public string webPage;
        public int numWordTotOfPage;
        public string user;
        public String word;
        public int fixNumb;
        public int fixTime;
        public String[] context;
        public int[] contextFixTime;
        public WordFixXML(String word, string webPage, int numWordTotOfPage, string user, int fixNumb, int fixTime, String[] context, int[] contextFixTime) 
        {
            this.word = word; this.webPage = webPage; this.numWordTotOfPage = numWordTotOfPage; this.user = user; this.fixNumb = fixNumb; this.fixTime = fixTime; this.context = context; this.contextFixTime = contextFixTime; 
        }
    };
    
    public class FixProcess
    {
        /// <summary>
        /// Elimina dalla lista dei gazePoint tutti i duplicati, ma unendo tali duplicati
        /// ne crea uno con la somma dei tempi;
        /// </summary>
        /// <param name="gList">lista GazePoint da filtrare</param>
        /// <returns></returns>
        public List<GazePoint> clearDuplicate(List<GazePoint> gList)
        {
            List<GazePoint> list = gList;
            GazePoint[] gArray = list.ToArray();
            List<GazePoint> final = new List<GazePoint>();
            for (int j=0; j<gArray.Length; j++)
            {
                for (int i=j+1; i<gArray.Length; i++)
                { 
                    if( list[j].equalsGazePoint(list[i]))
                    {
                        list[j].addTimeValue(list[i].timeFix);
                        list[j].numFix++;
                        list[i].zero();
                    }
                }
            }
            foreach( GazePoint g in gArray)
            {
                if(!(g.x == 0 && g.y==0 && g.timeFix==0))
                {
                    final.Add(g);
                }
            }
            return final;
        }
        
        /// <summary>
        /// Dalla lista discerne i termini dal contesto
        /// </summary>
        /// <param name="gaze"></param>
        /// <returns></returns>
        public List<GazePoint>[] getTerm(List<GazePoint> gList, int timeValue)
        {
            int time = timeValue;
            List<GazePoint> list = gList;
            List<GazePoint> terms = new List<GazePoint>();
            List<GazePoint> contextTerms = new List<GazePoint>(); ;
            List<GazePoint>[] ag = new List<GazePoint>[2]; ;
            //considero i termini chiave
            foreach (GazePoint g in list)
            {
                if (g.timeFix > time )
                {
                    terms.Add(g);  //lista dei termini
                }
                else
                {
                    contextTerms.Add(g);  //lista del possibile contesto
                }
            }
            ag[0] = terms;
            ag[1] = contextTerms;
            return ag;
        }

        /// <summary>
        /// A partire da una lista di gazePoint estrae i termini e il contesto e li restituisce come 
        /// una lista di WordXML
        /// </summary>
        /// <param name="wb">WebBrowse wb, il browser su cui si lavora</param>
        /// <param name="list">List di GazePoint da processare</param>
        /// <param name="trackBarValue">valore minimo di fissazione per il contesto</param>
        /// <param name="subject">l'utente corrente</param>
        /// <returns></returns>
        public List<WordFixXML> Capture(WebBrowser wb, List<GazePoint> list, int trackBarValue, string subject)
        {
            WebBrowser webBrowser = wb;
            List<GazePoint> GazePoints = list;
            int value = trackBarValue;
            string subjt = subject;
            List<WordFixXML> listXml = new List<WordFixXML>();
            WordFixXML wfxml;
            List<GazePoint>[] ag = new List<GazePoint>[2];
            string WordResult;
            Dictionary<string, int> ContextResult = new Dictionary<string, int>();
            //prendo il numero totale di parole nella pagina
            int numTotPageWord = (int)webBrowser.Document.InvokeScript("Conta");
            //cancello tutti i duplicati
            GazePoints = clearDuplicate(GazePoints);
            //carico in final tuttii termini e in contexterms i possivili contesti
            ag = getTerm(GazePoints, value);
            List<GazePoint> terms = ag[0];
            List<GazePoint> contextTerms = ag[1];
            
            Object[] objArray = new Object[2];
            foreach (GazePoint g in terms)
            {
                //prendo il termine
                objArray[0] = (Object)g.x;
                objArray[1] = (Object)g.y;
                WordResult = ((string)webBrowser.Document.InvokeScript("selectWord", objArray)).Trim();
                if (!WordResult.Equals(String.Empty))
                {
                    string cnt;
                    foreach (GazePoint gz in contextTerms)
                    {
                        //prendo il contesto, cioe' i gazepoint in un intorno
                        if (Math.Abs(g.x - gz.x) < webBrowser.Size.Width - 20 && Math.Abs(g.y - gz.y) < 60)
                        {
                            objArray[0] = (Object)gz.x;
                            objArray[1] = (Object)gz.y;
                            cnt = ((string)webBrowser.Document.InvokeScript("selectWord", objArray)).Trim();
                            if (!cnt.Equals(String.Empty))
                            {
                                ContextResult.Add(cnt, gz.timeFix);
                            }
                        }
                    }
                    //se ho preso tutti termini che mi servono per fare il contesto
                    //if (ContextResult.Count == cntxWordNumb)
                    //{
                    string[] context = ContextResult.Keys.ToArray();
                    int[] contextFixTime = ContextResult.Values.ToArray();
                    wfxml = new WordFixXML(WordResult, webBrowser.Url.AbsoluteUri, numTotPageWord, subjt, g.numFix, g.timeFix, context, contextFixTime);
                    listXml.Add(wfxml);
                    ContextResult.Clear();
                }
            }
            list.Clear();
            terms.Clear();
            contextTerms.Clear();
            return listXml;
        }

        /// <summary>
        /// Scrive una list WordFixXML su file
        /// </summary>
        /// <param name="lst">List-WordFixXML- da scrivere </param>
        public void WriteXML(List<WordFixXML> lst)
        {
            List<WordFixXML> list = lst;

            string session = String.Format("{0:dddd.MMMM.dd.yyyy.H.mm.ss}", DateTime.Now);
            MessageBox.Show(session);

            XmlTextWriter textWriter = new XmlTextWriter("D:\\XML\\" + session + ".xml", null);
            textWriter.Formatting = Formatting.Indented;

            // Opens the document
            textWriter.WriteStartDocument();
            // Write comments
            textWriter.WriteComment("First Comment XmlTextWriter Sample Example");
            // document
            textWriter.WriteStartElement("document", null);

            foreach (WordFixXML w in list)
            {
                // Start Word
                textWriter.WriteStartElement("word", null);

                    // Webpage
                    textWriter.WriteStartElement("webpage", null);
                    textWriter.WriteAttributeString("lenght", w.numWordTotOfPage.ToString());
                    textWriter.WriteString( w.webPage );
                    textWriter.WriteEndElement();

                    // User
                    textWriter.WriteStartElement("user", null);
                    textWriter.WriteString(w.user);
                    textWriter.WriteEndElement();

                    // Word name
                    textWriter.WriteStartElement("wname", null);
                    textWriter.WriteString( w.word );
                    textWriter.WriteEndElement();

                    // Number Fixations
                    textWriter.WriteStartElement("number_fixations", null);
                    textWriter.WriteString( w.fixNumb.ToString().Trim() );
                    textWriter.WriteEndElement();

                    // Time Fixations
                    textWriter.WriteStartElement("time_fixations", null);
                    textWriter.WriteString( w.fixTime.ToString() );
                    textWriter.WriteEndElement();

                    // idf
                    textWriter.WriteStartElement("idf", null);
                    textWriter.WriteString((w.fixTime * w.fixNumb).ToString());
                    textWriter.WriteEndElement();

                    // context
                    textWriter.WriteStartElement("context", null);
                    textWriter.WriteAttributeString("terms", w.context.Length.ToString());

                    // Start word context array
                    textWriter.WriteStartElement("word_context_array", null);

                    //term
                    foreach( string s in w.context )
                    {
                        textWriter.WriteStartElement("term", null);
                        textWriter.WriteString( s );
                        textWriter.WriteEndElement();
                    }
                    
                    // End word context array
                    textWriter.WriteEndElement();

                    // Start tfc_array
                    textWriter.WriteStartElement("tfc_array", null);

                    // time context
                    foreach( int i in w.contextFixTime)
                    {
                        textWriter.WriteStartElement("time", null);
                        textWriter.WriteString( i.ToString());
                        textWriter.WriteEndElement();

                    }
                    
                    // tfc_mean
                    textWriter.WriteStartElement("tfc_mean", null);
                    if (w.contextFixTime.Length==0)
                        textWriter.WriteString("0");
                    else
                        textWriter.WriteString( (w.contextFixTime.Sum() / w.contextFixTime.Length).ToString() );
                    textWriter.WriteEndElement();

                    // End tfc_array
                    textWriter.WriteEndElement();

                    // End context
                    textWriter.WriteEndElement();

                // End Word
                textWriter.WriteEndElement();

            }

            // Ends the document.
            textWriter.WriteEndDocument();


            // close writer
            textWriter.Flush();
            textWriter.Close();
        }

    }
}
